<!DOCTYPE html>
<!-- saved from url=(0127)https://docs.google.com/document/d/e/2PACX-1vQilbA9sQwFf4j2-VSh81m_8EkPuMlj_b7mEC4Y8NVqaVpja2mP8k1J3z79p4jrzI07VYgMRcVhXxDN/pub -->
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>WebPerfWG design call - July 10th 2019</title><link rel="shortcut icon" href="https://ssl.gstatic.com/docs/documents/images/kix-favicon7.ico"><meta name="referrer" content="strict-origin-when-cross-origin"><style type="text/css" nonce="">
      @import url("https://fonts.googleapis.com/css?family=Google+Sans");
      @import url("https://fonts.googleapis.com/css?family=Roboto");

      body {
        font-family: Roboto, arial, sans, sans-serif;
        margin: 0;
      }

      iframe {
        border: 0;
        frameborder: 0;
        height: 100%;
        width: 100%;
      }

      #header {
        align-items: center;
        background: white;
        border-bottom: 1px #ccc solid;
        display: flex;
        height: 60px;
        justify-content: space-between;
        position: fixed;
        top: 0;
        width: 100%;
        z-index: 100;
      }

      #header #title {
        font-family: 'Google Sans';
        font-size: large;
        margin: auto 0 auto 20px;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        width: 70%;
      }

      #header #interval {
        margin: auto 25px auto 0;
        font-family: Roboto;
        font-size: small;;
      }

      #footer {
        background: #f0f0f0;
        border-bottom: 1px #ccc solid;
        bottom: 0;
        font-family: Roboto;
        font-size: small;
        padding: 10px 10px;
        position: fixed;
        text-align: center;
        width: 100%;
      }

      #contents {
        padding: 100px 20% 50px 20%;
      }

      @media only screen and (max-device-width: 800px) {
        #header {
          border-bottom-width: 5px;
          height: auto;
          display: block;
        }

        #header #title {
          font-size: 3em;
          margin: auto 0 auto 20px;
          width: 90%;
        }

        #header #interval {
          font-size: 1.5em;
          margin: 10px 0 auto 25px;
        }

        #contents {
          padding: 150px 5% 80px;
        }

        #footer {
          font-size: 2em;
        }
      }

      .dash {
        padding: 0 6px;
      }
    </style></head><body><div id="header"><div id="title">WebPerfWG design call - July 10th 2019</div><div id="interval"><span></span></div></div><div id="contents"><style type="text/css">.lst-kix_bps0fo35x7e9-1>li:before{content:"\0025cb  "}.lst-kix_bps0fo35x7e9-2>li:before{content:"\0025a0  "}ul.lst-kix_bps0fo35x7e9-8{list-style-type:none}.lst-kix_bps0fo35x7e9-7>li:before{content:"\0025cb  "}li.li-bullet-0:before{margin-left:-18pt;white-space:nowrap;display:inline-block;min-width:18pt}.lst-kix_bps0fo35x7e9-0>li:before{content:"\0025cf  "}.lst-kix_bps0fo35x7e9-8>li:before{content:"\0025a0  "}ul.lst-kix_bps0fo35x7e9-1{list-style-type:none}ul.lst-kix_bps0fo35x7e9-0{list-style-type:none}ul.lst-kix_bps0fo35x7e9-3{list-style-type:none}ul.lst-kix_bps0fo35x7e9-2{list-style-type:none}ul.lst-kix_bps0fo35x7e9-5{list-style-type:none}ul.lst-kix_bps0fo35x7e9-4{list-style-type:none}.lst-kix_bps0fo35x7e9-6>li:before{content:"\0025cf  "}ul.lst-kix_bps0fo35x7e9-7{list-style-type:none}ul.lst-kix_bps0fo35x7e9-6{list-style-type:none}.lst-kix_bps0fo35x7e9-5>li:before{content:"\0025a0  "}.lst-kix_bps0fo35x7e9-3>li:before{content:"\0025cf  "}.lst-kix_bps0fo35x7e9-4>li:before{content:"\0025cb  "}ol{margin:0;padding:0}table td,table th{padding:0}.c4{margin-left:72pt;padding-top:0pt;padding-left:0pt;padding-bottom:0pt;line-height:1.15;orphans:2;widows:2;text-align:left}.c1{margin-left:36pt;padding-top:0pt;padding-left:0pt;padding-bottom:0pt;line-height:1.15;orphans:2;widows:2;text-align:left}.c5{margin-left:108pt;padding-top:0pt;padding-left:0pt;padding-bottom:0pt;line-height:1.15;orphans:2;widows:2;text-align:left}.c0{color:#000000;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:11pt;font-family:"Arial";font-style:normal}.c9{color:#000000;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:16pt;font-family:"Arial";font-style:normal}.c7{padding-top:18pt;padding-bottom:6pt;line-height:1.15;page-break-after:avoid;orphans:2;widows:2;text-align:left}.c10{padding-top:0pt;padding-bottom:0pt;line-height:1.15;orphans:2;widows:2;text-align:left;height:11pt}.c11{padding-top:0pt;padding-bottom:0pt;line-height:1.15;orphans:2;widows:2;text-align:left}.c6{text-decoration-skip-ink:none;-webkit-text-decoration-skip:none;color:#1155cc;text-decoration:underline}.c8{background-color:#ffffff;max-width:468pt;padding:72pt 72pt 72pt 72pt}.c2{color:inherit;text-decoration:inherit}.c3{padding:0;margin:0}.title{padding-top:0pt;color:#000000;font-size:26pt;padding-bottom:3pt;font-family:"Arial";line-height:1.15;page-break-after:avoid;orphans:2;widows:2;text-align:left}.subtitle{padding-top:0pt;color:#666666;font-size:15pt;padding-bottom:16pt;font-family:"Arial";line-height:1.15;page-break-after:avoid;orphans:2;widows:2;text-align:left}li{color:#000000;font-size:11pt;font-family:"Arial"}p{margin:0;color:#000000;font-size:11pt;font-family:"Arial"}h1{padding-top:20pt;color:#000000;font-size:20pt;padding-bottom:6pt;font-family:"Arial";line-height:1.15;page-break-after:avoid;orphans:2;widows:2;text-align:left}h2{padding-top:18pt;color:#000000;font-size:16pt;padding-bottom:6pt;font-family:"Arial";line-height:1.15;page-break-after:avoid;orphans:2;widows:2;text-align:left}h3{padding-top:16pt;color:#434343;font-size:14pt;padding-bottom:4pt;font-family:"Arial";line-height:1.15;page-break-after:avoid;orphans:2;widows:2;text-align:left}h4{padding-top:14pt;color:#666666;font-size:12pt;padding-bottom:4pt;font-family:"Arial";line-height:1.15;page-break-after:avoid;orphans:2;widows:2;text-align:left}h5{padding-top:12pt;color:#666666;font-size:11pt;padding-bottom:4pt;font-family:"Arial";line-height:1.15;page-break-after:avoid;orphans:2;widows:2;text-align:left}h6{padding-top:12pt;color:#666666;font-size:11pt;padding-bottom:4pt;font-family:"Arial";line-height:1.15;page-break-after:avoid;font-style:italic;orphans:2;widows:2;text-align:left}</style><div class="c8"><h2 class="c7" id="h.wyyy4mpvjdfi"><span class="c9">Participants</span></h2><p class="c11"><span class="c0">Alex Christensen, Maxime Villancourt, Yoav Weiss, Todd Reifsteck, Benjamin De Kosnik, Andrew Comminos, Will Hawkins, Ryosuke Niwa, Phil Walton, Tim Dresser, Nicolás Peña, Nic Jansma, Eric Lawrence</span></p><h2 class="c7" id="h.z73kc3hwtvup"><span class="c9">Admin</span></h2><p class="c11"><span class="c0"><b>Next meeting</b>: Aug 1st 11am PST</span></p><h2 class="c7" id="h.4siaa1r0p4qd"><span class="c9">Gargantua, the Working Group dashboard project - Philippe</span></h2><ul class="c3 lst-kix_bps0fo35x7e9-0 start"><li class="c1 li-bullet-0"><span><b>Demo</b>: </span><span class="c6"><a class="c2" href="https://www.google.com/url?q=https://www.w3.org/2019/07/webperf-example.html&amp;sa=D&amp;source=editors&amp;ust=1613235453978000&amp;usg=AOvVaw3Ly97zJgdI7qHo8VAxehZN">https://www.w3.org/2019/07/webperf-example.html</a></span></li><li class="c1 li-bullet-0"><span class="c0">Philippe</span></li></ul><ul class="c3 lst-kix_bps0fo35x7e9-1 start"><li class="c4 li-bullet-0"><span class="c0">We have a lot of data, but you have to know where to look</span></li><li class="c4 li-bullet-0"><span class="c0">Gargantua is about exposing this data</span></li><li class="c4 li-bullet-0"><span class="c0">Needs</span></li></ul><ul class="c3 lst-kix_bps0fo35x7e9-2 start"><li class="c5 li-bullet-0"><span class="c0">Public page for the rest of the world to see what we’re working on</span></li><li class="c5 li-bullet-0"><span class="c0">A page that’s useful for us: GH issues, spec status</span></li><li class="c5 li-bullet-0"><span class="c0">For the chairs - with more details</span></li></ul><ul class="c3 lst-kix_bps0fo35x7e9-1"><li class="c4 li-bullet-0"><span><b>Underlying data</b>: </span><span class="c6"><a class="c2" href="https://www.google.com/url?q=https://www.w3.org/PM/Groups/browse.html?gid%3D45211%26query%3Dactive-specifications&amp;sa=D&amp;source=editors&amp;ust=1613235453979000&amp;usg=AOvVaw0jtWRq1bTOMU0Q0WQR45tn">https://www.w3.org/PM/Groups/browse.html?gid=45211&amp;query=active-specifications</a></span></li><li class="c4 li-bullet-0"><span class="c0">Also links to wpt.fyi, but ad-hoc way to link directory to a spec. Trying to make it clearer</span></li><li class="c4 li-bullet-0"><span class="c0">Done on the client, so risks DoSing the related servers</span></li></ul><ul class="c3 lst-kix_bps0fo35x7e9-2 start"><li class="c5 li-bullet-0"><span class="c0">Plan to encourage folks at the Hackathon to optimize this</span></li></ul><ul class="c3 lst-kix_bps0fo35x7e9-1"><li class="c4 li-bullet-0"><span class="c0">We can play with it with an API key. W3C accounts can also create their own API key</span></li><li class="c4 li-bullet-0"><span class="c0">Continues to iterate over this, please surface data needs</span></li><li class="c4 li-bullet-0"><span class="c0"><b>Nicolás</b>: way to see issues?</span></li><li class="c4 li-bullet-0"><span class="c0"><b>Philippe</b>: yes, with a 24H delay, because we crawl GH every night, to avoid hitting limits</span></li><li class="c4 li-bullet-0"><span class="c0"><b>Todd</b>: Wanted to show numbers and link to GH, rather than displaying everything</span></li><li class="c4 li-bullet-0"><span class="c0"><b>Yoav</b>: possible to generate on the server?</span></li><li class="c4 li-bullet-0"><span class="c0"><b>Philippe</b>: yeah, talked to our system folks</span></li><li class="c4 li-bullet-0"><span class="c0"><b>Todd</b>: Looks really good. Only question is how fast can we have it?</span></li><li class="c4 li-bullet-0"><span><b>Philippe</b>: Code is on GH: </span><span class="c6"><a class="c2" href="https://www.google.com/url?q=https://github.com/w3c/gargantua&amp;sa=D&amp;source=editors&amp;ust=1613235453980000&amp;usg=AOvVaw2uCsUBjr9DN-UPsrWPZC2-">https://github.com/w3c/gargantua</a></span></li></ul><ul class="c3 lst-kix_bps0fo35x7e9-2 start"><li class="c5 li-bullet-0"><span class="c0">Created own framework, because it’s lazy loading the data, in order to avoid overwhelming the browser</span></li></ul><ul class="c3 lst-kix_bps0fo35x7e9-1"><li class="c4 li-bullet-0"><span class="c0">Next steps - Hackathon before TPAC</span></li></ul><ul class="c3 lst-kix_bps0fo35x7e9-2 start"><li class="c5 li-bullet-0"><span>All the tool folks will be there</span></li></ul><h2 class="c7" id="h.2r2t2v32z6hh"><span class="c6"><a class="c2" href="https://www.google.com/url?q=https://docs.google.com/presentation/d/1sJns8zk2J5mRWqYtWe5EynOhptcmHqF25TlwSWq-0aQ/edit?usp%3Dsharing&amp;sa=D&amp;source=editors&amp;ust=1613235453980000&amp;usg=AOvVaw0-PoEd8nVhGTBz_qjXlCVt">Upload Compression</a></span><span class="c9">&nbsp;- Andrew</span></h2><ul class="c3 lst-kix_bps0fo35x7e9-0"><li class="c1 li-bullet-0"><span class="c0"><b>Andrew</b>: Idea informally floated - talked about adding gzip to JS profiling</span></li></ul><ul class="c3 lst-kix_bps0fo35x7e9-1 start"><li class="c4 li-bullet-0"><span class="c0">Folks suggested breaking out the compression format</span></li><li class="c4 li-bullet-0"><span class="c0"><b>An interface for compression algorithms</b>: gzip, brotli, zstd</span></li><li class="c4 li-bullet-0"><span class="c0">Use-cases for complex apps as well as analytics vendors</span></li></ul><ul class="c3 lst-kix_bps0fo35x7e9-2 start"><li class="c5 li-bullet-0"><span class="c0">FB saw large reliability improvements from client-side compression</span></li></ul><ul class="c3 lst-kix_bps0fo35x7e9-1"><li class="c4 li-bullet-0"><span class="c0">Why not a polyfill?</span></li></ul><ul class="c3 lst-kix_bps0fo35x7e9-2 start"><li class="c5 li-bullet-0"><span class="c0">WASM was too large and not as fast as native. Requires data copying</span></li><li class="c5 li-bullet-0"><span class="c0">Also UAs already ship this, so why not</span></li></ul><ul class="c3 lst-kix_bps0fo35x7e9-1"><li class="c4 li-bullet-0"><span class="c0">Requirements</span></li></ul><ul class="c3 lst-kix_bps0fo35x7e9-2 start"><li class="c5 li-bullet-0"><span class="c0">Async</span></li><li class="c5 li-bullet-0"><span class="c0">Uniform interface, not codec specific</span></li><li class="c5 li-bullet-0"><span class="c0">Avoid extra allocations and copies</span></li><li class="c5 li-bullet-0"><span class="c0">Throttle for low CPU devices - in control of the developer</span></li></ul><ul class="c3 lst-kix_bps0fo35x7e9-0"><li class="c1 li-bullet-0"><span class="c0"><b>Ben</b>: Way to query what compression algorithms are available?</span></li><li class="c1 li-bullet-0"><span class="c0"><b>Andrew</b>: yeah should be feature detectable. getCompressorType or something like that makes sense.</span></li><li class="c1 li-bullet-0"><span class="c0"><b>Andrew</b>: Proposed API includes entry points through Streams and ArrayBuffer. To avoid extra allocations, the ArrayBuffer input transfers outside the script’s control, so we could reuse the same input allocation, which is useful regardless of codec.</span></li><li class="c1 li-bullet-0"><span class="c0"><b>Philippe</b>: Are you aware of past proposals on WICG?</span></li><li class="c1 li-bullet-0"><span class="c0"><b>Andrew</b>: didn’t know but will look into them.</span></li></ul><ul class="c3 lst-kix_bps0fo35x7e9-1 start"><li class="c4 li-bullet-0"><span>Past discussions</span><span class="c0">:</span></li></ul><ul class="c3 lst-kix_bps0fo35x7e9-2 start"><li class="c5 li-bullet-0"><span class="c6"><a class="c2" href="https://www.google.com/url?q=https://discourse.wicg.io/t/a-zip-api-in-the-browser/14&amp;sa=D&amp;source=editors&amp;ust=1613235453982000&amp;usg=AOvVaw0Bd7Uu2O51PC0hCdMKKSuS">https://discourse.wicg.io/t/a-zip-api-in-the-browser/14</a></span></li><li class="c5 li-bullet-0"><span class="c6"><a class="c2" href="https://www.google.com/url?q=https://discourse.wicg.io/t/need-for-gzip-deflate-api/1237&amp;sa=D&amp;source=editors&amp;ust=1613235453982000&amp;usg=AOvVaw3GpZxMT7PqC071F0bC4JG9">https://discourse.wicg.io/t/need-for-gzip-deflate-api/1237</a></span></li><li class="c5 li-bullet-0"><span class="c6"><a class="c2" href="https://www.google.com/url?q=https://discourse.wicg.io/t/compression-for-form-submission-request-bodies-from-the-browser/2838&amp;sa=D&amp;source=editors&amp;ust=1613235453982000&amp;usg=AOvVaw2V07oj-IhXgRMGcsqMcENv">https://discourse.wicg.io/t/compression-for-form-submission-request-bodies-from-the-browser/2838</a></span></li><li class="c5 li-bullet-0"><span class="c6"><a class="c2" href="https://www.google.com/url?q=https://discourse.wicg.io/t/interest-and-use-cases-for-transcoding-streams/3027&amp;sa=D&amp;source=editors&amp;ust=1613235453983000&amp;usg=AOvVaw0Wkv44qniVz8-repkhHy5W">https://discourse.wicg.io/t/interest-and-use-cases-for-transcoding-streams/3027</a></span></li></ul><ul class="c3 lst-kix_bps0fo35x7e9-0"><li class="c1 li-bullet-0"><span class="c0"><b>Philippe</b>: also, did you think about video compression as well?</span></li><li class="c1 li-bullet-0"><span class="c0"><b>Andrew</b>: We could… not familiar with WebRTC, but this could be leveraged for something like that</span></li><li class="c1 li-bullet-0"><span class="c0"><b>Todd</b>: The dependency here is that not all APIs currently include streams, but they’d need to support it to benefit from that</span></li><li class="c1 li-bullet-0"><span class="c0"><b>Andrew</b>: There’s also an ArrayBuffer entry point. We might also add a DOMString entry point in the future</span></li><li class="c1 li-bullet-0"><span class="c0"><b>Todd</b>: Want to avoid web sites doing wasteful copies. Stream help devs do the right thing.</span></li><li class="c1 li-bullet-0"><span class="c0"><b>Andrew</b>: Right. That was the motivation behind making the ArrayBuffer transferable. Devs would need to deliberately copy to shoot themselves in the foot.</span></li><li class="c1 li-bullet-0"><span class="c0"><b>Todd</b>: Like it conceptually, but concerned it will cause footguns in the real world.</span></li><li class="c1 li-bullet-0"><span class="c0"><b>Andrew</b>: Maybe we should name it to make it explicit that the ArrayBuffer is transferable.</span></li><li class="c1 li-bullet-0"><span class="c0"><b>Ryosuke</b>: Primary use case is to send this back to the server, why isn’t this an option in Fetch?</span></li><li class="c1 li-bullet-0"><span class="c0"><b>Andrew</b>: Wanted to make it general purpose. There are cases where you want compress localStorage, etc. Streams make it very easy to compose, also into Fetch.</span></li><li class="c1 li-bullet-0"><span class="c0"><b>Ryosuke</b>: But now everything is single threaded, you have to go back to the main thread</span></li><li class="c1 li-bullet-0"><span class="c0"><b>Andrew</b>: Not necessarily. You may need a sync spot on the main thread to spawn it off.</span></li><li class="c1 li-bullet-0"><span class="c0"><b>Yoav</b>: why?</span></li><li class="c1 li-bullet-0"><span class="c0"><b>Andrew</b>: Actually, readable streams should enable passing compressed things to fetch() without going through the main thread</span></li><li class="c1 li-bullet-0"><span class="c0"><b>Ryosuke</b>: Oh, so in the example you’re waiting, but it’s not really needed.</span></li><li class="c1 li-bullet-0"><span class="c0"><b>Andrew</b>: Yeah, we’d only need to await in the ArrayBuffer case</span></li><li class="c1 li-bullet-0"><span class="c0"><b>Ryosuke</b>: still better to do this in Fetch</span></li><li class="c1 li-bullet-0"><span class="c0"><b>Yoav</b>: We have use-cases to have that separately - enables flexibility on client side storage as well as mixing payloads that require different algorithms</span></li><li class="c1 li-bullet-0"><span class="c0"><b>Ryosuke</b>: I see your point. But how does the decoder know how to decode? Headers?</span></li><li class="c1 li-bullet-0"><span class="c0"><b>Andrew</b>: The server will have to interpret it and decode on the server side. No headers involved. So the server would need to always expect certain codecs, or insert headers manually. Doesn’t seem far-fetched that you’d want to always assume compressed data.</span></li><li class="c1 li-bullet-0"><span class="c0"><b>Ryosuke</b>: That assumed you’re writing your servers. Standard servers won’t help you. You’d need to manually deal with decoding.</span></li><li class="c1 li-bullet-0"><span class="c0"><b>Yoav</b>: Sure, but no standard server right now decompresses the payload (e.g. if you use content-encoding on the upload).</span></li><li class="c1 li-bullet-0"><span class="c0"><b>Nic</b>: You can convince Apache, but it’s not on by default</span></li><li class="c1 li-bullet-0"><span class="c0"><b>Yoav</b>: Yeah, so it requires some negotiation between the client and the server. Whereas here if the developer knows the backend collecting the data, handling the payload is their responsibility.</span></li><li class="c1 li-bullet-0"><span class="c0"><b>Nic</b>: Want to add my support for this. Use a lot of CPU and ship code to compress RT and UT data. The browser can better do that: either stream based approach of a Fetch option</span></li><li class="c1 li-bullet-0"><span><b>Todd</b>: What ryosuke says is that server will eventually support this, so value to explore this. No reason for </span><span>that not being the default</span><span class="c0">.</span></li><li class="c1 li-bullet-0"><span class="c0"><b>Andrew</b>: There’s value in exploring fetch as a separate topic. useful to have both.</span></li><li class="c1 li-bullet-0"><span class="c0"><b>Todd</b>: useful to have the ability to compress separately. Maybe also useful to have a unique string that represents the input and is standardized and reusable, that goes with the data and informs the decoder how it was compressed. (regardless of decoder on the server, in localstorage after version changes, etc)</span></li><li class="c1 li-bullet-0"><span class="c0"><b>Yoav</b>: that seems useful</span></li><li class="c1 li-bullet-0"><span class="c0"><b>Andrew</b>: sounds good. Many use cases where one would vary the compression format?</span></li><li class="c1 li-bullet-0"><span class="c0"><b>Yoav</b>: There are cases where you can invest more processing power in some parts of the stream (e.g. brotli 11), but other parts you want to compress on the fly. But could be tackled in separate streams that are combined.</span></li><li class="c1 li-bullet-0"><span class="c0"><b>Andrew</b>: Yeah, making it general enough should be good enough</span></li><li class="c1 li-bullet-0"><span class="c0"><b>Ryosuke</b>: some compression algorithms may be more efficient than others. A single algo does not cover everything. Maybe need something like Web Media where there’s a preferred algorithm based on compression efficiency, power efficiency.</span></li><li class="c1 li-bullet-0"><span class="c0"><b>Andrew</b>: Sounds good. May want to provide abstractions across algorithms, or to have each codec take its own “bag of flags”.</span></li><li class="c1 li-bullet-0"><span class="c0"><b>Yoav</b>: bag of flags is probably better, as there are many knobs involved beyond compression level. E.g. in order to implement SSH with gzip you need specific flushing parameters.</span></li><li class="c1 li-bullet-0"><span class="c0"><b>Yoav</b>: Also, dictionaries. Brotli and gzip can have external dictionaries that can help reduce compressed data for specific formats and use cases. Downloading a dictionary can help upload transfers.</span></li><li class="c1 li-bullet-0"><span class="c0"><b>Andrew</b>: Definitely thought of external dictionaries. Thought it would be tackled by “bag of flags”. Not sure how to persist them.</span></li><li class="c1 li-bullet-0"><span class="c0"><b>Yoav</b>: Yeah, I thought of user land persistency.</span></li><li class="c1 li-bullet-0"><span class="c0"><b>Andrew</b>: Anything beyond “bag of flags” for this use-case?</span></li><li class="c1 li-bullet-0"><span class="c0"><b>Yoav</b>: Not sure. It’d be a large bag...</span></li><li class="c1 li-bullet-0"><span class="c0"><b>Phil</b>: For the RUM/analytics case, making it async would be a burden and not usable in beforeunload. An option to Fetch would be better along with keep-alive, letting the browser do that work off-main-thread.</span></li><li class="c1 li-bullet-0"><span class="c0"><b>Yoav</b>: There’s a real extensible web play here, we need to provide the primitives *and* integrate them into fetch() </span></li><li class="c1 li-bullet-0"><span class="c0"><b>Ben</b>: around compression levels, we would prefer to pick the algorithm and its parameters.</span></li><li class="c1 li-bullet-0"><span class="c0"><b>Andrew</b>: bag of flags it is!</span></li></ul><h2 class="c7" id="h.csqnsreqd5wo"><span>Element Timing and text aggregation - </span><span>Nicolás</span></h2><ul class="c3 lst-kix_bps0fo35x7e9-1"><li class="c1 li-bullet-0"><span class="c6"><a class="c2" href="https://www.google.com/url?q=https://docs.google.com/document/d/1WWFxpuLpbMs3Jri1b2Y6O0rNldv0FAFcMDe-IGGuQ54/edit&amp;sa=D&amp;source=editors&amp;ust=1613235453986000&amp;usg=AOvVaw33-SPmNX0O9l6UcEB4XBm-">https://docs.google.com/document/d/1WWFxpuLpbMs3Jri1b2Y6O0rNldv0FAFcMDe-IGGuQ54/edit</a></span></li><li class="c1 li-bullet-0"><span class="c0"><b>Nicolás</b>: wanted to talk about the way we tackled text aggregation</span></li></ul><ul class="c3 lst-kix_bps0fo35x7e9-2 start"><li class="c4 li-bullet-0"><span class="c0"><b>High level problem</b>: ET wants to expose “important” text content, but since text nodes are not elements, we need to specify which text nodes belong</span></li><li class="c4 li-bullet-0"><span class="c0">Considered several approaches and ended up with aggregating a text node to the nearest containing block ancestor</span></li></ul><ul class="c3 lst-kix_bps0fo35x7e9-3 start"><li class="c5 li-bullet-0"><span class="c0"><b>Notion of depth</b>: arbitrary, links increase depth, but shouldn’t have that impact</span></li><li class="c5 li-bullet-0"><span class="c0"><b>Top level elements</b>: high maintenance</span></li><li class="c5 li-bullet-0"><span class="c0"><b>Phrasing content</b>: could work, but harder to implement, so containing block was chosen</span></li></ul><ul class="c3 lst-kix_bps0fo35x7e9-2"><li class="c4 li-bullet-0"><span class="c0">*shows examples*</span></li></ul><ul class="c3 lst-kix_bps0fo35x7e9-1"><li class="c1 li-bullet-0"><span class="c0"><b>Todd</b>: notions are standardized, right?</span></li><li class="c1 li-bullet-0"><span class="c0"><b>Tim</b>: Yeah, also devs know blocking elements way more than phrasing content</span></li><li class="c1 li-bullet-0"><span class="c0"><b>Will</b>: If a dev wants to learn something on a specific text, can they wrap it and annotate it? Is that the idea?</span></li><li class="c1 li-bullet-0"><span class="c0"><b>Nicolás</b>: block level element would change layout</span></li><li class="c1 li-bullet-0"><span class="c0"><b>Tim</b>: we should think about that, that’s a great question</span></li><li class="c1 li-bullet-0"><span class="c0"><b>Will</b>: want to see if devs can specify an override</span></li><li class="c1 li-bullet-0"><span class="c0"><b>Yoav</b>: would a span work</span></li><li class="c1 li-bullet-0"><span class="c0"><b>Tim</b>: currently it won’t work, we tried to avoid reporting things multiple times, but maybe we should. We need to figure it out</span></li><li class="c1 li-bullet-0"><span class="c0">&nbsp;<b>Nicolás</b>: I’d think that the problem is often the other way around. Text nodes are generally very small. Not sure if this is a real problem, but worth looking into it</span></li></ul><p class="c10"><span class="c0"></span></p></div></div><div id="footer"><span>Published by <a target="_blank" title="Learn more about Google Drive" href="https://docs.google.com/">Google Drive</a></span><span class="dash">–</span><a href="https://docs.google.com/u/0/abuse?id=AKkXjow-uWF_FQPnoG8qa3fLpyNP5Pyc4jNfpDtsVaig55sEyipWEOPce_Dz1Ype01l7OKzn9n9QFgKeuyDTsEo:0">Report Abuse</a></div><script type="text/javascript" nonce="">(function(){/*

 Copyright The Closure Library Authors.
 SPDX-License-Identifier: Apache-2.0
*/
var aa="function"==typeof Object.defineProperties?Object.defineProperty:function(a,b,c){if(a==Array.prototype||a==Object.prototype)return a;a[b]=c.value;return a};function ba(a){a=["object"==typeof globalThis&&globalThis,a,"object"==typeof window&&window,"object"==typeof self&&self,"object"==typeof global&&global];for(var b=0;b<a.length;++b){var c=a[b];if(c&&c.Math==Math)return c}throw Error("Cannot find global object");}var ca=ba(this);
function da(a,b){if(b)a:{var c=ca;a=a.split(".");for(var d=0;d<a.length-1;d++){var e=a[d];if(!(e in c))break a;c=c[e]}a=a[a.length-1];d=c[a];b=b(d);b!=d&&null!=b&&aa(c,a,{configurable:!0,writable:!0,value:b})}}var ea="function"==typeof Object.create?Object.create:function(a){function b(){}b.prototype=a;return new b},fa;
if("function"==typeof Object.setPrototypeOf)fa=Object.setPrototypeOf;else{var ha;a:{var ia={a:!0},ja={};try{ja.__proto__=ia;ha=ja.a;break a}catch(a){}ha=!1}fa=ha?function(a,b){a.__proto__=b;if(a.__proto__!==b)throw new TypeError(a+" is not extensible");return a}:null}var ka=fa;
function h(a,b){a.prototype=ea(b.prototype);a.prototype.constructor=a;if(ka)ka(a,b);else for(var c in b)if("prototype"!=c)if(Object.defineProperties){var d=Object.getOwnPropertyDescriptor(b,c);d&&Object.defineProperty(a,c,d)}else a[c]=b[c];a.o=b.prototype}da("Object.is",function(a){return a?a:function(b,c){return b===c?0!==b||1/b===1/c:b!==b&&c!==c}});var l=this||self;function la(){}function ma(a){var b=typeof a;return"object"==b&&null!=a||"function"==b}
function na(a,b){var c=Array.prototype.slice.call(arguments,1);return function(){var d=c.slice();d.push.apply(d,arguments);return a.apply(this,d)}}function oa(a,b){function c(){}c.prototype=b.prototype;a.o=b.prototype;a.prototype=new c;a.prototype.constructor=a;a.B=function(d,e,f){for(var g=Array(arguments.length-2),k=2;k<arguments.length;k++)g[k-2]=arguments[k];return b.prototype[e].apply(d,g)}}function pa(a){return a};var qa=Array.prototype.indexOf?function(a,b){return Array.prototype.indexOf.call(a,b,void 0)}:function(a,b){if("string"===typeof a)return"string"!==typeof b||1!=b.length?-1:a.indexOf(b,0);for(var c=0;c<a.length;c++)if(c in a&&a[c]===b)return c;return-1};function ra(a,b,c){for(var d in a)b.call(c,a[d],d,a)};var m;function p(a,b){this.i=a===sa&&b||"";this.j=ta}p.prototype.h=!0;p.prototype.g=function(){return this.i};var ta={},sa={};var ua=String.prototype.trim?function(a){return a.trim()}:function(a){return/^[\s\xa0]*([\s\S]*?)[\s\xa0]*$/.exec(a)[1]},va=/&/g,wa=/</g,xa=/>/g,ya=/"/g,za=/'/g,Aa=/\x00/g,Ba=/[\x00&<>"']/;function Ca(a,b){return a<b?-1:a>b?1:0};function q(a,b){this.i=b===r?a:""}q.prototype.h=!0;q.prototype.g=function(){return this.i.toString()};q.prototype.toString=function(){return this.i.toString()};function u(a){return a instanceof q&&a.constructor===q?a.i:"type_error:SafeUrl"}
var Da=/^(?:audio\/(?:3gpp2|3gpp|aac|L16|midi|mp3|mp4|mpeg|oga|ogg|opus|x-m4a|x-matroska|x-wav|wav|webm)|font\/\w+|image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp|x-icon)|video\/(?:mpeg|mp4|ogg|webm|quicktime|x-matroska))(?:;\w+=(?:\w+|"[\w;,= ]+"))*$/i,Ea=/^data:(.*);base64,[a-z0-9+\/]+=*$/i,Fa=/^(?:(?:https?|mailto|ftp):|[^:/?#]*(?:[/?#]|$))/i;function Ga(a){if(a instanceof q)return a;a="object"==typeof a&&a.h?a.g():String(a);Fa.test(a)||(a="about:invalid#zClosurez");return new q(a,r)}
var r={},Ha=new q("about:invalid#zClosurez",r);var v;a:{var Ia=l.navigator;if(Ia){var Ja=Ia.userAgent;if(Ja){v=Ja;break a}}v=""}function w(a){return-1!=v.indexOf(a)};function x(a,b,c){this.i=c===Ka?a:""}x.prototype.h=!0;x.prototype.g=function(){return this.i.toString()};x.prototype.toString=function(){return this.i.toString()};var Ka={};function La(a,b,c,d){a=a instanceof q?a:Ga(a);b=b||l;c=c instanceof p?c instanceof p&&c.constructor===p&&c.j===ta?c.i:"type_error:Const":c||"";return void 0!==d?b.open(u(a),c,d,void 0):b.open(u(a),c)};function Ma(a){Ma[" "](a);return a}Ma[" "]=la;function y(a,b,c){return Object.prototype.hasOwnProperty.call(a,b)?a[b]:a[b]=c(b)};var Na=w("Opera"),z=w("Trident")||w("MSIE"),Oa=w("Edge"),Pa=Oa||z,Qa=w("Gecko")&&!(-1!=v.toLowerCase().indexOf("webkit")&&!w("Edge"))&&!(w("Trident")||w("MSIE"))&&!w("Edge"),Ra=-1!=v.toLowerCase().indexOf("webkit")&&!w("Edge"),Sa=w("Macintosh");function Ta(){var a=l.document;return a?a.documentMode:void 0}var Ua;
a:{var Va="",Wa=function(){var a=v;if(Qa)return/rv:([^\);]+)(\)|;)/.exec(a);if(Oa)return/Edge\/([\d\.]+)/.exec(a);if(z)return/\b(?:MSIE|rv)[: ]([^\);]+)(\)|;)/.exec(a);if(Ra)return/WebKit\/(\S+)/.exec(a);if(Na)return/(?:Version)[ \/]?(\S+)/.exec(a)}();Wa&&(Va=Wa?Wa[1]:"");if(z){var Xa=Ta();if(null!=Xa&&Xa>parseFloat(Va)){Ua=String(Xa);break a}}Ua=Va}var Ya=Ua,Za={},$a;if(l.document&&z){var ab=Ta();$a=ab?ab:parseInt(Ya,10)||void 0}else $a=void 0;var bb=$a;function cb(a){return y(a.prototype,"$$generatedClassName",function(){return"Class$obf_"+{valueOf:function(){return++db}}})}var db=1E3;function A(){}A.prototype.u=function(){return this.j||(Object.defineProperties(this,{j:{value:++eb,enumerable:!1}}),this.j)};A.prototype.toString=function(){var a=B(fb(gb(this.constructor)))+"@";var b=(this.u()>>>0).toString(16);return a+B(b)};function D(){}h(D,A);D.prototype.i=function(a){this.h=a;if(a instanceof Object)try{a.A=this}catch(b){}};function hb(a){a.h instanceof Error&&(Error.captureStackTrace?Error.captureStackTrace(a.h):a.h.stack=Error().stack)}D.prototype.toString=function(){var a=fb(gb(this.constructor)),b=this.l;return null==b?a:B(a)+": "+B(b)};function ib(){}h(ib,D);function jb(){}h(jb,ib);var eb=0;function E(){}h(E,jb);E.prototype.i=function(a){jb.prototype.i.call(this,Object.is(this.g,"__noinit__")?a:this.g)};function kb(){}h(kb,E);function lb(a,b){return"string"==typeof a?a.charCodeAt(b):a.g(b)};function B(a){return null==a?"null":a.toString()}function mb(a){return 65536<=a?B(String.fromCharCode((55296+((a-65536|0)>>10&1023)|0)&65535))+B(String.fromCharCode((56320+((a-65536|0)&1023)|0)&65535)):String.fromCharCode(a&65535)}function nb(a,b){var c=b,d=a.length,e;b=lb(a,(e=c,c=c+1|0,e));var f;if(e=55296<=b&&56319>=b&&c<d)a=f=lb(a,c),e=56320<=a&&57343>=a;var g;e?g=65536+((b&1023)<<10)+(f&1023)|0:g=b;return g};function ob(a,b){this.h=a;this.g=b}h(ob,A);function fb(a){var b=cb(a.h);0!=a.g&&(b="L"+B(b)+";");a=a.g;for(var c="",d=0;d<a;d=d+1|0)c=B(c)+"[";return B(c)+B(b)}ob.prototype.toString=function(){return"class "+B(fb(this))};function gb(a){var b=0;return y(a.prototype,"$$class/"+b,function(){return new ob(a,b)})};function pb(a,b){return null==a?a:b?decodeURI(a):decodeURIComponent(a)};var qb=/^(?:([^:/?#.]+):)?(?:\/\/(?:([^/?#]*)@)?([^/#?]*?)(?::([0-9]+))?(?=[/#?]|$))?([^?#]+)?(?:\?([^#]*))?(?:#([\S\s]*))?$/;function rb(a){a=qb.exec(a);for(var b=[],c=0;7>=c;c=c+1|0)a.length<=c||null==a[c]?b.push(null):b.push(a[c]);return b}
function sb(a,b){var c=a.indexOf(mb(35));c=0>c?a.length:c;a:{var d=0;for(var e=b.length;0<(d=a.indexOf(b,d))&&d<c;){var f=nb(a,d-1|0);if(38==f||63==f){if((d+e|0)>=a.length)break a;f=nb(a,d+e|0);if(61==f||38==f||35==f)break a}d=d+(e+1)|0}d=-1}if(0>d)return null;e=a.indexOf(mb(38),d);if(0>e||e>c)e=c;d=d+(b.length+1)|0;b=Math.min(a.length,d);a=a.substr(b,Math.min(a.length,Math.max(d,e))-b|0);c=" ";for(b=0;0<=(b=c.indexOf("\\",b));)36==c.charCodeAt(b+1|0)?(d=B(c.substr(0,b|0))+"$",e=b=b+1|0,c=d+B(c.substr(e))):
(d=B(c.substr(0,b|0)),e=b=b+1|0,c=d+B(c.substr(e)));a=a.replace(/\+/g,c);return pb(a,!1)};function F(a,b){this.h=b;for(var c=[],d=!0,e=a.length-1;0<=e;e--){var f=a[e]|0;d&&f==b||(c[e]=f,d=!1)}this.g=c}var tb={};function ub(a){return-128<=a&&128>a?y(tb,a,function(b){return new F([b|0],0>b?-1:0)}):new F([a|0],0>a?-1:0)}function G(a){if(isNaN(a)||!isFinite(a))return H;if(0>a)return I(G(-a));for(var b=[],c=1,d=0;a>=c;d++)b[d]=a/c|0,c*=4294967296;return new F(b,0)}var H=ub(0),J=ub(1),vb=ub(16777216);
function K(a){if(-1==a.h)return-K(I(a));for(var b=0,c=1,d=0;d<a.g.length;d++){var e=L(a,d);b+=(0<=e?e:4294967296+e)*c;c*=4294967296}return b}F.prototype.toString=function(a){a=a||10;if(2>a||36<a)throw Error("radix out of range: "+a);if(M(this))return"0";if(-1==this.h)return"-"+I(this).toString(a);for(var b=G(Math.pow(a,6)),c=this,d="";;){var e=wb(c,b).g;c=N(c,O(e,b));var f=((0<c.g.length?c.g[0]:c.h)>>>0).toString(a);c=e;if(M(c))return f+d;for(;6>f.length;)f="0"+f;d=f+d}};
function L(a,b){return 0>b?0:b<a.g.length?a.g[b]:a.h}function M(a){if(0!=a.h)return!1;for(var b=0;b<a.g.length;b++)if(0!=a.g[b])return!1;return!0}function P(a,b){a=N(a,b);return-1==a.h?-1:M(a)?0:1}function I(a){for(var b=a.g.length,c=[],d=0;d<b;d++)c[d]=~a.g[d];return(new F(c,~a.h)).add(J)}F.prototype.abs=function(){return-1==this.h?I(this):this};
F.prototype.add=function(a){for(var b=Math.max(this.g.length,a.g.length),c=[],d=0,e=0;e<=b;e++){var f=d+(L(this,e)&65535)+(L(a,e)&65535),g=(f>>>16)+(L(this,e)>>>16)+(L(a,e)>>>16);d=g>>>16;f&=65535;g&=65535;c[e]=g<<16|f}return new F(c,c[c.length-1]&-2147483648?-1:0)};function N(a,b){return a.add(I(b))}
function O(a,b){if(M(a)||M(b))return H;if(-1==a.h)return-1==b.h?O(I(a),I(b)):I(O(I(a),b));if(-1==b.h)return I(O(a,I(b)));if(0>P(a,vb)&&0>P(b,vb))return G(K(a)*K(b));for(var c=a.g.length+b.g.length,d=[],e=0;e<2*c;e++)d[e]=0;for(e=0;e<a.g.length;e++)for(var f=0;f<b.g.length;f++){var g=L(a,e)>>>16,k=L(a,e)&65535,t=L(b,f)>>>16,n=L(b,f)&65535;d[2*e+2*f]+=k*n;Q(d,2*e+2*f);d[2*e+2*f+1]+=g*n;Q(d,2*e+2*f+1);d[2*e+2*f+1]+=k*t;Q(d,2*e+2*f+1);d[2*e+2*f+2]+=g*t;Q(d,2*e+2*f+2)}for(e=0;e<c;e++)d[e]=d[2*e+1]<<16|
d[2*e];for(e=c;e<2*c;e++)d[e]=0;return new F(d,0)}function Q(a,b){for(;(a[b]&65535)!=a[b];)a[b+1]+=a[b]>>>16,a[b]&=65535,b++}function S(a,b){this.g=a;this.h=b}
function wb(a,b){if(M(b))throw Error("division by zero");if(M(a))return new S(H,H);if(-1==a.h)return b=wb(I(a),b),new S(I(b.g),I(b.h));if(-1==b.h)return b=wb(a,I(b)),new S(I(b.g),b.h);if(30<a.g.length){if(-1==a.h||-1==b.h)throw Error("slowDivide_ only works with positive integers.");for(var c=J,d=b;0>=P(d,a);)c=xb(c,1),d=xb(d,1);var e=T(c,1),f=T(d,1);d=T(d,2);for(c=T(c,2);!M(d);){var g=f.add(d);0>=P(g,a)&&(e=e.add(c),f=g);d=T(d,1);c=T(c,1)}b=N(a,O(e,b));return new S(e,b)}for(e=H;0<=P(a,b);){c=Math.max(1,
Math.floor(K(a)/K(b)));d=Math.ceil(Math.log(c)/Math.LN2);d=48>=d?1:Math.pow(2,d-48);f=G(c);for(g=O(f,b);-1==g.h||0<P(g,a);)c-=d,f=G(c),g=O(f,b);M(f)&&(f=J);e=e.add(f);a=N(a,g)}return new S(e,a)}F.prototype.and=function(a){for(var b=Math.max(this.g.length,a.g.length),c=[],d=0;d<b;d++)c[d]=L(this,d)&L(a,d);return new F(c,this.h&a.h)};F.prototype.or=function(a){for(var b=Math.max(this.g.length,a.g.length),c=[],d=0;d<b;d++)c[d]=L(this,d)|L(a,d);return new F(c,this.h|a.h)};
F.prototype.xor=function(a){for(var b=Math.max(this.g.length,a.g.length),c=[],d=0;d<b;d++)c[d]=L(this,d)^L(a,d);return new F(c,this.h^a.h)};function xb(a,b){var c=b>>5;b%=32;for(var d=a.g.length+c+(0<b?1:0),e=[],f=0;f<d;f++)e[f]=0<b?L(a,f-c)<<b|L(a,f-c-1)>>>32-b:L(a,f-c);return new F(e,a.h)}function T(a,b){var c=b>>5;b%=32;for(var d=a.g.length-c,e=[],f=0;f<d;f++)e[f]=0<b?L(a,f+c)>>>b|L(a,f+c+1)<<32-b:L(a,f+c);return new F(e,a.h)};N(xb(J,32),J);N(xb(J,128),J);function yb(a){a&&"function"==typeof a.v&&a.v()};function U(){this.h=this.h;this.g=this.g}U.prototype.h=!1;U.prototype.v=function(){this.h||(this.h=!0,this.j())};U.prototype.j=function(){if(this.g)for(;this.g.length;)this.g.shift()()};var zb=!z||9<=Number(bb),Ab=!z||9<=Number(bb),Bb=z&&!y(Za,"9",function(){for(var a=0,b=ua(String(Ya)).split("."),c=ua("9").split("."),d=Math.max(b.length,c.length),e=0;0==a&&e<d;e++){var f=b[e]||"",g=c[e]||"";do{f=/(\d*)(\D*)(.*)/.exec(f)||["","","",""];g=/(\d*)(\D*)(.*)/.exec(g)||["","","",""];if(0==f[0].length&&0==g[0].length)break;a=Ca(0==f[1].length?0:parseInt(f[1],10),0==g[1].length?0:parseInt(g[1],10))||Ca(0==f[2].length,0==g[2].length)||Ca(f[2],g[2]);f=f[3];g=g[3]}while(0==a)}return 0<=a}),
Cb=function(){if(!l.addEventListener||!Object.defineProperty)return!1;var a=!1,b=Object.defineProperty({},"passive",{get:function(){a=!0}});try{l.addEventListener("test",la,b),l.removeEventListener("test",la,b)}catch(c){}return a}();function Db(a,b){this.type=a;this.g=this.target=b;this.defaultPrevented=!1}Db.prototype.h=function(){this.defaultPrevented=!0};function V(a,b){Db.call(this,a?a.type:"");this.relatedTarget=this.g=this.target=null;this.button=this.screenY=this.screenX=this.clientY=this.clientX=0;this.key="";this.metaKey=this.shiftKey=this.altKey=this.ctrlKey=!1;this.state=null;this.pointerId=0;this.pointerType="";this.i=null;if(a){var c=this.type=a.type,d=a.changedTouches&&a.changedTouches.length?a.changedTouches[0]:null;this.target=a.target||a.srcElement;this.g=b;if(b=a.relatedTarget){if(Qa){a:{try{Ma(b.nodeName);var e=!0;break a}catch(f){}e=
!1}e||(b=null)}}else"mouseover"==c?b=a.fromElement:"mouseout"==c&&(b=a.toElement);this.relatedTarget=b;d?(this.clientX=void 0!==d.clientX?d.clientX:d.pageX,this.clientY=void 0!==d.clientY?d.clientY:d.pageY,this.screenX=d.screenX||0,this.screenY=d.screenY||0):(this.clientX=void 0!==a.clientX?a.clientX:a.pageX,this.clientY=void 0!==a.clientY?a.clientY:a.pageY,this.screenX=a.screenX||0,this.screenY=a.screenY||0);this.button=a.button;this.key=a.key||"";this.ctrlKey=a.ctrlKey;this.altKey=a.altKey;this.shiftKey=
a.shiftKey;this.metaKey=a.metaKey;this.pointerId=a.pointerId||0;this.pointerType="string"===typeof a.pointerType?a.pointerType:Eb[a.pointerType]||"";this.state=a.state;this.i=a;a.defaultPrevented&&V.o.h.call(this)}}oa(V,Db);var Fb=[1,4,2],Eb={2:"touch",3:"pen",4:"mouse"};V.prototype.h=function(){V.o.h.call(this);var a=this.i;if(a.preventDefault)a.preventDefault();else if(a.returnValue=!1,Bb)try{if(a.ctrlKey||112<=a.keyCode&&123>=a.keyCode)a.keyCode=-1}catch(b){}};var Gb="closure_listenable_"+(1E6*Math.random()|0);var Hb=0;function Ib(a,b,c,d,e){this.listener=a;this.g=null;this.src=b;this.type=c;this.capture=!!d;this.h=e;this.key=++Hb;this.m=this.s=!1}function Jb(a){a.m=!0;a.listener=null;a.g=null;a.src=null;a.h=null};function Kb(a){this.src=a;this.g={};this.h=0}Kb.prototype.add=function(a,b,c,d,e){var f=a.toString();a=this.g[f];a||(a=this.g[f]=[],this.h++);var g;a:{for(g=0;g<a.length;++g){var k=a[g];if(!k.m&&k.listener==b&&k.capture==!!d&&k.h==e)break a}g=-1}-1<g?(b=a[g],c||(b.s=!1)):(b=new Ib(b,this.src,f,!!d,e),b.s=c,a.push(b));return b};function Lb(a,b){var c=b.type;if(c in a.g){var d=a.g[c],e=qa(d,b),f;(f=0<=e)&&Array.prototype.splice.call(d,e,1);f&&(Jb(b),0==a.g[c].length&&(delete a.g[c],a.h--))}};var Mb="closure_lm_"+(1E6*Math.random()|0),Nb={},Ob=0;function Pb(a,b,c,d,e){if(d&&d.once)return Qb(a,b,c,d,e);if(Array.isArray(b)){for(var f=0;f<b.length;f++)Pb(a,b[f],c,d,e);return null}c=Rb(c);return a&&a[Gb]?a.g.add(String(b),c,!1,ma(d)?!!d.capture:!!d,e):Sb(a,b,c,!1,d,e)}
function Sb(a,b,c,d,e,f){if(!b)throw Error("Invalid event type");var g=ma(e)?!!e.capture:!!e,k=Tb(a);k||(a[Mb]=k=new Kb(a));c=k.add(b,c,d,g,f);if(c.g)return c;d=Ub();c.g=d;d.src=a;d.listener=c;if(a.addEventListener)Cb||(e=g),void 0===e&&(e=!1),a.addEventListener(b.toString(),d,e);else if(a.attachEvent)a.attachEvent(Vb(b.toString()),d);else if(a.addListener&&a.removeListener)a.addListener(d);else throw Error("addEventListener and attachEvent are unavailable.");Ob++;return c}
function Ub(){var a=Wb,b=Ab?function(c){return a.call(b.src,b.listener,c)}:function(c){c=a.call(b.src,b.listener,c);if(!c)return c};return b}function Qb(a,b,c,d,e){if(Array.isArray(b)){for(var f=0;f<b.length;f++)Qb(a,b[f],c,d,e);return null}c=Rb(c);return a&&a[Gb]?a.g.add(String(b),c,!0,ma(d)?!!d.capture:!!d,e):Sb(a,b,c,!0,d,e)}
function Xb(a){if("number"!==typeof a&&a&&!a.m){var b=a.src;if(b&&b[Gb])Lb(b.g,a);else{var c=a.type,d=a.g;b.removeEventListener?b.removeEventListener(c,d,a.capture):b.detachEvent?b.detachEvent(Vb(c),d):b.addListener&&b.removeListener&&b.removeListener(d);Ob--;(c=Tb(b))?(Lb(c,a),0==c.h&&(c.src=null,b[Mb]=null)):Jb(a)}}}function Vb(a){return a in Nb?Nb[a]:Nb[a]="on"+a}
function Yb(a,b,c,d){var e=!0;if(a=Tb(a))if(b=a.g[b.toString()])for(b=b.concat(),a=0;a<b.length;a++){var f=b[a];f&&f.capture==c&&!f.m&&(f=Zb(f,d),e=e&&!1!==f)}return e}function Zb(a,b){var c=a.listener,d=a.h||a.src;a.s&&Xb(a);return c.call(d,b)}
function Wb(a,b){if(a.m)return!0;if(!Ab){if(!b)a:{b=["window","event"];for(var c=l,d=0;d<b.length;d++)if(c=c[b[d]],null==c){b=null;break a}b=c}d=b;b=new V(d,this);c=!0;if(!(0>d.keyCode||void 0!=d.returnValue)){a:{var e=!1;if(0==d.keyCode)try{d.keyCode=-1;break a}catch(g){e=!0}if(e||void 0==d.returnValue)d.returnValue=!0}d=[];for(e=b.g;e;e=e.parentNode)d.push(e);a=a.type;for(e=d.length-1;0<=e;e--){b.g=d[e];var f=Yb(d[e],a,!0,b);c=c&&f}for(e=0;e<d.length;e++)b.g=d[e],f=Yb(d[e],a,!1,b),c=c&&f}return c}return Zb(a,
new V(b,this))}function Tb(a){a=a[Mb];return a instanceof Kb?a:null}var $b="__closure_events_fn_"+(1E9*Math.random()>>>0);function Rb(a){if("function"===typeof a)return a;a[$b]||(a[$b]=function(b){return a.handleEvent(b)});return a[$b]};function W(a){U.call(this);this.l=a;this.i={}}oa(W,U);var ac=[];function bc(a){ra(a.i,function(b,c){this.i.hasOwnProperty(c)&&Xb(b)},a);a.i={}}W.prototype.j=function(){W.o.j.call(this);bc(this)};W.prototype.handleEvent=function(){throw Error("EventHandler.handleEvent not implemented");};function cc(a){U.call(this);this.i=a||document.body;this.l=new W(this);a=na(yb,this.l);this.h?a():(this.g||(this.g=[]),this.g.push(a));a=this.l;var b=this.i,c=this.u,d="click";Array.isArray(d)||(d&&(ac[0]=d.toString()),d=ac);for(var e=0;e<d.length;e++){var f=Pb(b,d[e],c||a.handleEvent,!1,a.l||a);if(!f)break;a.i[f.key]=f}}h(cc,U);
cc.prototype.u=function(a){if(!(!(zb?0==a.i.button:"click"==a.type||a.i.button&Fb[0])||Sa&&a.ctrlKey||a.defaultPrevented))for(var b=a.target;b&&b!=this.i;){if(b.tagName&&"a"==b.tagName.toLowerCase()){var c=b.getAttribute("href")||b.getAttributeNS("http://www.w3.org/1999/xlink","href"),d=c;try{var e=rb(c)[3];var f;if(f="www.google.com"===pb(e,!0)){var g=rb(c)[5];f="/url"===pb(g,!0)}if(f){var k=sb(c,"q");d=k?k:sb(c,"url")}}catch(C){a:{var t=C;if(null!=t){var n=t.A;if(null!=n){C=n;break a}}if(t instanceof
TypeError){var R=n=new kb;R.l=B(t);hb(R);n.g="__noinit__";n.g=t;n.i(new TypeError(n));t=n}else R=n=new E,R.l=B(t),hb(R),n.g="__noinit__",n.g=t,n.i(Error(n)),t=n;C=t}if(!(C instanceof ib))throw C.h;}d=null!=d?d:"";if(c!=d){e=void 0;b={target:"_blank",noreferrer:!0};c=window;d instanceof q?f=d:(f="undefined"!=typeof d.href?d.href:String(d),f instanceof q||(f="object"==typeof f&&f.h?f.g():String(f),Fa.test(f)?f=new q(f,r):(f=String(f),f=f.replace(/(%0A|%0D)/g,""),f=(g=f.match(Ea))&&Da.test(g[1])?new q(f,
r):null)),f=f||Ha);d=b.target||d.target;g=[];for(e in b)switch(e){case "width":case "height":case "top":case "left":g.push(e+"="+b[e]);break;case "target":case "noopener":case "noreferrer":break;default:g.push(e+"="+(b[e]?1:0))}e=g.join(",");if((w("iPhone")&&!w("iPod")&&!w("iPad")||w("iPad")||w("iPod"))&&c.navigator&&c.navigator.standalone&&d&&"_self"!=d)e="A",g=document,e=String(e),"application/xhtml+xml"===g.contentType&&(e=e.toLowerCase()),g=e=g.createElement(e),f=f instanceof q?f:Ga(f),g.href=
u(f),e.setAttribute("target",d),b.noreferrer&&e.setAttribute("rel","noreferrer"),b=document.createEvent("MouseEvent"),b.initMouseEvent("click",!0,!0,c,1),e.dispatchEvent(b);else if(b.noreferrer){if(c=La("",c,d,e),b=u(f),c){Pa&&-1!=b.indexOf(";")&&(b="'"+b.replace(/'/g,"%27")+"'");c.opener=null;Ba.test(b)&&(-1!=b.indexOf("&")&&(b=b.replace(va,"&amp;")),-1!=b.indexOf("<")&&(b=b.replace(wa,"&lt;")),-1!=b.indexOf(">")&&(b=b.replace(xa,"&gt;")),-1!=b.indexOf('"')&&(b=b.replace(ya,"&quot;")),-1!=b.indexOf("'")&&
(b=b.replace(za,"&#39;")),-1!=b.indexOf("\x00")&&(b=b.replace(Aa,"&#0;")));b='<meta name="referrer" content="no-referrer"><meta http-equiv="refresh" content="0; url='+b+'">';if(void 0===m)if(d=null,(e=l.trustedTypes)&&e.createPolicy){try{d=e.createPolicy("goog#html",{createHTML:pa,createScript:pa,createScriptURL:pa})}catch(C){l.console&&l.console.error(C.message)}m=d}else m=d;b=(d=m)?d.createHTML(b):b;b=new x(b,null,Ka);(c=c.document)&&c.write&&(c.write(b instanceof x&&b.constructor===x?b.i:"type_error:SafeHtml"),
c.close())}}else(c=La(f,c,d,e))&&b.noopener&&(c.opener=null);a.h();break}}b=b.parentNode}};function dc(a){new cc(a)}var X=["DOCS_installLinkReferrerSanitizer"],Y=l;X[0]in Y||"undefined"==typeof Y.execScript||Y.execScript("var "+X[0]);for(var Z;X.length&&(Z=X.shift());)X.length||void 0===dc?Y[Z]&&Y[Z]!==Object.prototype[Z]?Y=Y[Z]:Y=Y[Z]={}:Y[Z]=dc;}).call(this);
</script><script type="text/javascript" nonce="">DOCS_installLinkReferrerSanitizer();</script></body></html>